package com.m3958.firstgwt.server.servlet;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.m3958.firstgwt.client.types.ServerErrorCode;
import com.m3958.firstgwt.client.types.SmartOperationName;
import com.m3958.firstgwt.server.accesschecker.BaseChecker;
import com.m3958.firstgwt.server.command.AddCommand;
import com.m3958.firstgwt.server.command.AdminCommand;
import com.m3958.firstgwt.server.command.Command;
import com.m3958.firstgwt.server.command.CustomCommand;
import com.m3958.firstgwt.server.command.DiskFileCommand;
import com.m3958.firstgwt.server.command.FetchCommand;
import com.m3958.firstgwt.server.command.NoOperationCommand;
import com.m3958.firstgwt.server.command.RemoveCommand;
import com.m3958.firstgwt.server.command.UpdateCommand;
import com.m3958.firstgwt.server.exception.SmartJpaException;
import com.m3958.firstgwt.server.model.DiskFile;
import com.m3958.firstgwt.server.model.Token;
import com.m3958.firstgwt.server.service.AppUtilService;
import com.m3958.firstgwt.server.service.IframeResultStoreService;
import com.m3958.firstgwt.server.service.ModelAndDao;
import com.m3958.firstgwt.server.service.ReqParaService;
import com.m3958.firstgwt.server.session.ErrorMessages;
import com.m3958.firstgwt.server.types.SmartError;
import com.m3958.firstgwt.shared.type.SmartParameterName;


/**
 * author jianglibo@gmail.com
 *  
 */
@Singleton
public class SmartCFUDServiceImpl extends HttpServlet{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@Inject 
	private Injector injector;
	
	@Inject
	private AppUtilService autils;
	
	@Inject
	private IframeResultStoreService irss;
	
	private static Set<String> allowAddModels = new HashSet<String>();
	
	static{
		
	}
	
	
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException{
		doPost(req, res);
	}
	
	
	@SuppressWarnings("unused")
	private void writeExcel(HttpServletRequest req, HttpServletResponse res,ByteArrayOutputStream baos) throws IOException{
		res.setContentType("application/vnd.ms-excel");
		res.setHeader("Content-Disposition", "attachment; filename=lgb.xls");
		baos.writeTo(res.getOutputStream());
	}

	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse res)
	throws ServletException, IOException {
		
		ErrorMessages errors = injector.getInstance(ErrorMessages.class);
		ReqParaService reqps = injector.getInstance(ReqParaService.class);
		
		if(DiskFile.class.getName().equals(req.getParameter(SmartParameterName.MODEL_NAME))){
			DiskFileCommand dfc = injector.getInstance(DiskFileCommand.class);
			try {
				dfc.execute();
			} catch (SmartJpaException e) {}
			return;
		}
		
		if(!allowAnanymousAdd(req, res)){
			if(!doCheck(req, res)){
				errors.addError(new SmartError("操作拒绝！", ServerErrorCode.ACCESS_DENY));
			}
		}
		
		if(errors.isEmpty()){
			String s = req.getParameter(SmartParameterName.OPERATION_TYPE);
			SmartOperationName opName = SmartOperationName.NO_OPERATION;
			if(s!=null){
				opName = SmartOperationName.valueOf(s.toUpperCase());
			}
			
			Command c = null;
			switch (opName) {
			case FETCH:
				c = injector.getInstance(FetchCommand.class);
				break;
			case REMOVE:
				c = injector.getInstance(RemoveCommand.class);
				break;
			case UPDATE:
				c = injector.getInstance(UpdateCommand.class);
				break;
			case ADD:
				c = injector.getInstance(AddCommand.class);
				break;
			case CUSTOM:
				c = injector.getInstance(CustomCommand.class);
				break;
			case ADMIN:
				c = injector.getInstance(AdminCommand.class);
				break;
			default:
				c = injector.getInstance(NoOperationCommand.class);
				break;
			}
			
			try {
				c.execute();
			} catch (SmartJpaException e) {
				e.printStackTrace();
				errors.addError(new SmartError(e.getMessage(), ServerErrorCode.JPA_ERROR));
			} catch (Exception e) {
				e.printStackTrace();
				errors.addError(new SmartError(e.getMessage(), ServerErrorCode.JPA_ERROR));
			}			
		}
		

		
		if(!errors.isEmpty()){
			JSONObject jo = autils.getJsonErrorResponseJsonObject(res);
			JSONObject m3958jo = new JSONObject();
			m3958jo.element("tid", reqps.getTid());
			jo.getJSONObject("response").element("m3958extra", m3958jo);
			
			if(reqps.isJsonp()){
				autils.writeJsonpResponse(res, jo.toString(), req.getParameter("callback"));
			}else{
				if(reqps.isIframe()){
					irss.addIframeResult(reqps.getTid(), jo.toString());
					autils.writeHtmlResponseWithTemplate(res, "empty", "");
				}else{
					autils.writeJsonResponse(res, jo.toString());
				}
			}
		}
	}
	
	private boolean allowAnanymousAdd(HttpServletRequest req, HttpServletResponse res){
		String modelName = req.getParameter(SmartParameterName.MODEL_NAME);
		if(Token.class.getName().equals(modelName))return true;
		String optype = req.getParameter(SmartParameterName.OPERATION_TYPE);
		if(SmartOperationName.ADD.getValue().equals(optype)){
			if(allowAddModels.contains(modelName)){
				return true;
			}
		}
		return false;
	}
	
	private boolean doCheck(HttpServletRequest req, HttpServletResponse res){
		String modelName = req.getParameter(SmartParameterName.MODEL_NAME);
		ModelAndDao modelConfig = injector.getInstance(ModelAndDao.class);
		BaseChecker checker = modelConfig.getCheckerInstance(modelName);
		return checker.doCheck();
	}
}
